package com.tom.architect02.mnbase.annotation.fs;

import android.view.View;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// activity 使用
public class InjectUtils {
    // 注入的方法。
    public static void inject(Object context) {
        injectClick(context);
    }

    private static void injectClick(Object context) {
        Class<?> clazz = context.getClass(); // 拿到Activity
        Method[] methods = clazz.getDeclaredMethods(); // 拿到Activity所有的方法

        for (Method method : methods) { // 循环判断所有方法
            Annotation[] annotations = method.getAnnotations(); // 拿到方法所有的注解 annotations
            for (Annotation annotation : annotations) { // 循环遍历Annotation
                Class<?> annotationClass = annotation.annotationType();
                EventBase eventBase = annotationClass.getAnnotation(EventBase.class); // 反射判断：是否有事件注解 @EventBase
                // 判断是否是注解的处理程序：onClick，onLongClick，不是就continue。排除掉不需要的方法。
                if (eventBase == null) continue;

//                btn1.setOnClickListener(new View.OnClickListener() {
//                    @Override
//                    public void onClick(View v) { //Proxy代理替换掉onClick，在代理里面调用abc方法。
//                        // ...
//                    }
//                });
                // 需要的事件的代码：取到事件的三要素
                // 1.setOnClickListener 订阅关系
                String listenerSetter = eventBase.listenerSetter();
                // 2.new View.OnClickListener 事件本身
                Class<?> listenerType = eventBase.listenerType();
                // 3.事件处理程序，代理处理，方法会被代理掉。
                String callBackMethod = eventBase.callbackMethod();

                // 得到3个要素后，执行onClick代码：对接动态代理 InvocationHandler。
                Method valueMethod = null;
                try {
                    valueMethod = annotationClass.getDeclaredMethod("value"); // 拿到value方法，相当于注解里面的方法。
                    int[] viewIds = (int[]) valueMethod.invoke(annotation); // 拿到所有的id
                    for (int viewId : viewIds) {
                        // 为了得到Button对象，先找到 Activity的 findViewById方法。
                        Method findViewById = clazz.getMethod("findViewById", int.class);
                        View view = (View) findViewById.invoke(context, viewId); // 得到 view，btn1对象。
                        if (view == null) continue; // 为空，不处理。

                        // context--activity; click--method  执行Activity的click方法：method
                        ListenerInvocationHandler listenerInvocationHandler = new ListenerInvocationHandler(context, method);
                        // 代理的初始化，hook Framework源码，经常用到。
                        Object proxy = Proxy.newProxyInstance(listenerType.getClassLoader(),
                                new Class[]{listenerType}, listenerInvocationHandler);
                        // 执行动作，拿到方法：view.setOnClickListener(new View.OnCLickListener()...)
                        // 方法名是：setOnClickListener;  参数是new View.OnCLickListener()...
                        Method onClickMethod = view.getClass().getMethod(listenerSetter, listenerType);
                        // 相当于，执行onClick方法,  执行view上面的onClick方法。
                        // 但是参数被代理对象代理掉了，所以接着执行ListenerInvocationHandler.invoke()方法，
                        // 在代理里面，又通过反射执行activity的 方法：activityMethod.invoke(activity, args)，相当于执行Activity里面的abc(View v)方法。
                        onClickMethod.invoke(view, proxy);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
